package com.zhenai.sys.framework.aspectj;

import cn.hutool.core.util.ObjectUtil;
import com.zhenai.bcus.common.base.utils.PhoneUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import com.zhenai.sys.framework.aspectj.context.VagueQueryUserInfoContext;

import java.lang.reflect.Field;
import java.util.Objects;

/**
 * 参数名含 keyword 或 phone 或 mobile 的，在 sys-user 弄一个AOP拦截，统一加密此参数的值
 *
 * @author ouxuxuan
 * @date 2024/7/1 18:07
 */
@Aspect
@Component
@Slf4j
public class VagueQueryUserInfoAspect {


    @Around("@annotation(org.springframework.web.bind.annotation.RequestMapping) ||@annotation(org.springframework.web.bind.annotation.PostMapping) || @annotation(org.springframework.web.bind.annotation.PutMapping) || @annotation(org.springframework.web.bind.annotation.GetMapping)")
    public Object intercept(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String[] paramNames = signature.getParameterNames();
        Object[] paramValues = joinPoint.getArgs();

        try {
            VagueQueryUserInfoContext.put(VagueQueryUserInfoContext.VagueQueryData.builder()
                    .keyType(queryValue(VagueQueryUserInfoContext.KEY_TYPE, paramNames, paramValues))
                    .keyword(queryValue(VagueQueryUserInfoContext.KEY_WORD, paramNames, paramValues))
//                    .keyword(PhoneUtils.encryptPhone(queryValue(KEY_WORD, paramNames, paramValues)))
                    .build());
            if (paramValues != null && paramValues.length > 0) {
                return joinPoint.proceed(paramValues);
            } else {
                return joinPoint.proceed();
            }
        } catch (Throwable e) {
            throw e;
        } finally {
            VagueQueryUserInfoContext.clearContext();
        }
    }

    private <T> T queryValue(String fieldName, String[] paramNames, Object[] paramValues) {
        T t = getRequestParams(fieldName, paramNames, paramValues);
        if (ObjectUtil.isNotEmpty(t)) {
            return t;
        }
        return getRequestBody(paramValues, fieldName);
    }

    private <T> T getRequestParams(String fieldName, String[] paramNames, Object[] paramValues) {
        for (int i = 0; i < paramNames.length; i++) {
            String name = paramNames[i];
            if (StringUtils.isNotEmpty(name) && name.contains(fieldName)) {
                if (!Objects.isNull(paramValues[i])) {
                    try {
                        return (T) paramValues[i];
                    } catch (Exception e) {
                    }
                }
            }
        }
        return null;
    }

    private <T> T getRequestBody(Object[] paramValues, String fieldName) {
        for (Object param : paramValues) {
            if (ObjectUtil.isNotEmpty(param)) {
                return getRequestBody(param, fieldName);
            }
        }
        return null;
    }

    public <T> T getRequestBody(Object obj, String fieldName) {
        try {
            Class<?> clazz = obj.getClass();
            Field field = getDeclaredField(clazz, fieldName);
            if (Objects.isNull(field)) { // 从父类获取
                field = getDeclaredField(clazz.getSuperclass(), fieldName);
            }
            if (field != null) {
                field.setAccessible(true);
                try {
                    Object FieldValue = field.get(obj);
                    if (ObjectUtil.isNotEmpty(FieldValue)) {
                        return (T) FieldValue;
                    }
                } catch (IllegalAccessException e) {
                    return null;
                }
            }
        } catch (Exception e) {
            log.error("获取自定义对象某个字段的值失败", e);
        }
        return null;
    }

    private Field getDeclaredField(Class<?> clazz, String fieldName) {
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            if (field.getName().equals(fieldName)) {
                return field;
            }
        }
        return null;
    }


}
